#include <future>
#include <iostream>

/**
 * @brief 基础：取值、阻塞、异常传递
 */
void test1()
{
    auto cal = []()
    {
        return 42;
    };

    std::promise<int> p{}; // 创建一个promise对象用于储存int类型的结果或异常
    auto f = p.get_future(); // 从promise中获取一个future对象f，该对象用来获取p中储存的数据
    std::thread t{
        [&]()
        {
            try
            {
                p.set_value(cal()); // 尝试调用cal函数并将结果设置到promise p 中
            }
            catch (...) // 捕获所有类型的异常
            {
                p.set_exception(std::current_exception()); // 如果cal抛出异常，则将当前异常设置到peromise中
            }
        }
    };

    try
    {
        // 如果future 对象 f 的get方法尝试获取由promise p 设置的值
        // f.get是阻塞操作，直到promise p 被设置值或者异常位置
        // 如果 promise p 存储的是一个值，则返回该值；如果存储的是异常，则在此处重新抛出该异常。
        std::cout << f.get() << std::endl;
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    t.join();
}

/**
 * @brief 非阻塞探测
 */
void test2()
{
    auto f = std::async(std::launch::async, []()
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(150)); // 休眠150毫秒
        return 7; // 返回数值7
    }); // 使用std::async启动一个异步任务，std::launch::async指定该任务必须在新线程执行

    // 等待100 ms并检查任务是否执行完成，如果执行完成则返回ready的状态
    if (f.wait_for(std::chrono::milliseconds(100)) == std::future_status::ready)
    {
        std::cout << f.get() << std::endl; // 阻塞操作，但这里已经执行完成，所以不会阻塞
    }
    else
    {
        std::cout << "Not ready yet" << std::endl;
        std::cout << f.get() << std::endl; // 未执行完成进行阻塞操作
    }
}

/**
 * @brief 共享一个结果
 */
void test3()
{
    auto f = std::async(std::launch::async, []()
    {
        return 10;
    }); // 使用std::async启动一个异步任务，std::launch::async指定该任务必须在新线程执行
    // shared_future允许多个线程共同使用
    // 可复制，复制后共享同一个内部状态
    // 内部使用引用计数机制管理共享状态，因此所有副本都都可以访问相同的结果
    std::shared_future<int> sf = f.share(); // 将是std::future转换为std::shared_future,转换后future将不再可用

    auto f1 = std::async(std::launch::async, [sf]()
    {
        // 采用值捕获的方式预防生命周期

        return sf.get() + 1; // 阻塞等待并将获取的结果+1
    });
    auto f2 = std::async(std::launch::async, [sf]()
    {
        return sf.get() * 2; // 阻塞等待并将获取的结果翻倍
    });

    std::cout << f1.get() << " " << f2.get() << std::endl;
}

/**
 * @brief
 * @tparam Callback 回调模板
 * @param cb 回调函数cb
 */
template <class Callback>
void ThirdPartyAsync(Callback cb)
{
    std::thread([cb = std::move(cb)/*按值捕获并移动到函数内部*/]() mutable
    {
        try
        {
            // do something
            cb(true, std::string{"PayLoad"});
        }
        catch (...)
        {
            cb(false, std::string{});
        }
    }).detach(); // 线程分离
}

std::future<std::string> Wrap()
{
    std::promise<std::string> p{};
    auto f = p.get_future();
    ThirdPartyAsync([p = std::move(p)](bool bOk, std::string strData) mutable
    {
        try
        {
            if (bOk)
            {
                p.set_value(std::move(strData));
            }
            else
            {
                p.set_exception(std::make_exception_ptr(std::runtime_error("failed")));
            }
        }
        catch (...)
        {
        }
    });
    return f;
}

void test4()
{
    auto f = Wrap();
    try
    {
        std::cout << f.get() << std::endl;
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

/**
 * @brief 最省心的任务启动器，显示并行
 */
void test5()
{
    auto heavy = [](int nVar)
    {
        return nVar * nVar;
    };

    auto f = std::async(std::launch::async, heavy, 21); // 启动一个线程执行heavy函数
    std::cout << "Main thread is doing something " << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));

    try
    {
        auto nResult = f.get();
        std::cout << "Result: " << nResult << std::endl;
    }
    catch (const std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
}

/**
 * @brief 延迟执行
 */
void test6()
{
    // 记录开始时间
    auto start_time = std::chrono::high_resolution_clock::now();

    // 使用 std::async 和 std::launch::deferred 创建一个异步任务
    auto f = std::async(std::launch::deferred, []()
    {
        // 不会创建新的线程
        std::this_thread::sleep_for(std::chrono::microseconds(10));
        return 123;
    });

    std::cout << f.get() << std::endl; // 此刻才开始执行
    // 记录获取结果的结束时间
    auto get_result_end = std::chrono::high_resolution_clock::now();

    // 记录总执行时间
    auto end_time = std::chrono::high_resolution_clock::now();
    auto total_duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
    std::cout << "Total time taken: " << total_duration.count() << " microseconds" << std::endl;

}

int main()
{
    // test1();
    // test2();
    // test3();
    // test4();
    // test5();
    test6();
    return 0;
}
